package com.googlecode.axolotl.prevayler;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
import org.codehaus.groovy.grails.commons.GrailsApplication;
import org.codehaus.groovy.grails.commons.GrailsDomainClass;
import org.codehaus.groovy.grails.plugins.support.aware.GrailsApplicationAware;
import org.prevayler.Prevayler;
import org.prevayler.PrevaylerFactory;
import org.prevayler.foundation.serialization.XStreamSerializer;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.transaction.TransactionStatus;

import com.googlecode.axolotl.Database;
import com.googlecode.axolotl.grails.GrailsDomainUtils;
import com.googlecode.axolotl.query.Query;


public class PrevaylerDatabase implements Database, GrailsApplicationAware {

	private GrailsApplication application;
	private Prevayler prevayler;

	
	public PrevaylerDatabase() {
		initialize();
	}
	
	
	public void setGrailsApplication(GrailsApplication grailsApplication) {
		this.application = grailsApplication;	
	}
	
	
	public TransactionStatus beginTransaction() {
		// TODO Auto-generated method stub
		return null;
	}

	public void commit(TransactionStatus status) {
		// TODO Auto-generated method stub

	}

	public void rollback(TransactionStatus status) {
		// TODO Auto-generated method stub

	}

	public Object load(Class clazz, Object id) {
		return ((Map) prevayler.prevalentSystem()).get(id);
	}

	
	public List loadIds(Query query) {
		return null;
	}


	public int count(Query query) {
		return -1;
	}


	public void insert(Object entity) {
		Object id = prevayler.execute( new NextIdQuery() );
		setIdentifierValue(entity, id);
		prevayler.execute( new InsertTransaction(id, entity) );
	}

	
	public void update(Object entity) {
		Object id = GrailsDomainUtils.getIdentifierValue(application, entity);
		prevayler.execute( new InsertTransaction(id, entity) );
	}
	

	public void delete(Object entity) {
		Object id = GrailsDomainUtils.getIdentifierValue(application, entity);
		prevayler.execute( new DeleteTransaction(id) );
	}
	
	
	private void initialize() {
		try {
            PrevaylerFactory factory = new PrevaylerFactory();
            factory.configurePrevalenceDirectory("prevaylator");
            factory.configurePrevalentSystem( new InMemoryStorage() );
            factory.configureJournalSerializer( new XStreamSerializer() );
            factory.configureSnapshotSerializer( new XStreamSerializer() );
            prevayler = factory.create();
//			prevayler = PrevaylerFactory.createPrevayler((Serializable) delegate, "pepe");
		}
		catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	
	protected GrailsDomainClass getDomainClass(Class clazz) {
		return (GrailsDomainClass) application.getArtefact(DomainClassArtefactHandler.TYPE, clazz.getName());
	}

	private void setIdentifierValue(Object entity, Object id) {
		BeanWrapper wrapper = (entity instanceof BeanWrapper) ? (BeanWrapper) entity : new BeanWrapperImpl(entity);
		GrailsDomainClass domainClass = getDomainClass(entity.getClass());
		wrapper.setPropertyValue( domainClass.getIdentifier().getName(), id );			
	}

}
